package server;

import client.dao.MessageDao;
import client.dao.UserDao;
import client.pojo.Message;
import client.pojo.User;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;

public class MultiChatServer {
    private static HashSet<ObjectOutputStream> writers = new HashSet<>();
    private static List<String> onlineUsers = new ArrayList<>();
    private static MessageDao messageDao = new MessageDao();
    private int clientNumber = 0;

    public static void main(String[] args) {
        UserDao userDao = new UserDao();
        userDao.updateAllUser();
        new MultiChatServer();
    }

    private MultiChatServer() {
        new Thread(() -> {
            try {
                //
                ServerSocket serverSocket = new ServerSocket(7777);
                System.out.println("Server started at " + new Date());
                while (true) {
                    // 创建一个socket，用来启动对外服务，接受客户端的连接
                    Socket socket = serverSocket.accept();
                    clientNumber++;
                    System.out.println("Starting Thread for Client " + clientNumber + "at " + new Date());
                    new Thread(new HandleClient(socket)).start();
                }
            }  catch (IOException e){
                e.printStackTrace();
            }
        }).start();
    }

    private class HandleClient implements Runnable {
        private ObjectOutputStream outputToFile;
        private ObjectInputStream inputFromClient;
        private Socket socket;
        private InputStream is;
        private OutputStream os;
        String userName;

        HandleClient(Socket socket) {
            this.socket = socket;
        }

        @Override
        public void run() {
            try {
                is = socket.getInputStream();
                os = socket.getOutputStream();
                inputFromClient = new ObjectInputStream(is);
                outputToFile = new ObjectOutputStream(os);
                writers.add(outputToFile);
                userName = (String) inputFromClient.readObject();
                System.out.println(userName + "已连接");
                User user = new User();
                user.setUserName(userName);
                UserDao userDao = new UserDao();
                if(userDao.checkUser(user)!=null&&userDao.checkUser(user).getState()==1){
                    outputToFile.writeObject("fail");
                    outputToFile.flush();
                    onlineUsers.remove(userName);
                    System.out.println("登录失败");
                }
                if(userDao.checkUser(user)!=null){
                    outputToFile.writeObject("success");
                    outputToFile.flush();
                    user.setState(1);
                    userDao.updateState(user);
                    onlineUsers.add(userName);
                    sendNotification();
                }
                if(userDao.checkUser(user)==null){
                    outputToFile.writeObject("success");
                    outputToFile.flush();
                    user.setState(1);
                    userDao.addUser(user);
                    onlineUsers.add(userName);
                    sendNotification();
                }
                while (socket.isConnected()) {
                    showHistory(outputToFile);
                    while (true) {
                        Message inputMessage = (Message) inputFromClient.readObject();
                        if (inputMessage != null) {
                            System.out.println(inputMessage);
                            write(inputMessage);
                            messageDao.saveMessage(inputMessage);
                        }
                    }
                }
            } catch (Exception e) {
                onlineUsers.remove(userName);
                writers.remove(outputToFile);
                UserDao userDao = new UserDao();
                User user = new User();
                user.setUserName(userName);
                user.setState(0);
                // 窗口关闭的时候用户状态更新为已下线
                userDao.updateState(user);
                sendNotification();
                System.out.println("窗口关闭，当前用户已下线");
            }
        }
    }

    private void write(Message msg) throws IOException {
        for (ObjectOutputStream writer : writers) {
            writer.writeObject(msg);
            writer.flush();
            writer.reset();
        }
    }

    private void sendNotification() {
        try {
            String users = "";
            for (String onlineUser : onlineUsers) {
                users += onlineUser + '\n';
            }
            Message message = new Message("", users, new Date()+"", 1);
            write(message);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 显示历史消息
     */
    private void showHistory(ObjectOutputStream os) {
        String res = "";
        messageDao = new MessageDao();
        List<Message> allMessage = messageDao.getAllMessage();
        for (Message message : allMessage) {
            res += (message.getUserName() + "(" + message.getSendTime() + ")" + "\n" + message.getContent() +
                    "\n\n");
        }
        try {
            //只给新连接上的用户显示历史消息
            os.writeObject(new Message("",res,"",2));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


}
